namespace WP7Contrib.Services.BingMaps.Model
{
    using System;
    using System.Device.Location;
    using Common;

    public class RouteDestination : BaseModel, IEquatable<RouteDestination>,
                                               ICloneable<RouteDestination>
    {
        private GeoCoordinate point;
        private Landmark landmark;
        private Address address;

        public RouteDestination()
        {
            this.point = new GeoCoordinate();
            this.landmark = new Landmark();
            this.address = new Address();
        }

        public GeoCoordinate Point
        {
            get
            {
                return this.point;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.point, value, () => this.Point);
            }
        }

        public bool HasPoint
        {
            get { return this.point != null && this.point != GeoCoordinate.Unknown; }
        }

        public Landmark Landmark
        {
            get
            {
                return this.landmark;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.landmark, value, () => this.Landmark);
            }
        }

        public bool HasLandmark
        {
            get { return this.landmark != null && this.landmark != Landmark.Empty; }
        }

        public Address Address
        {
            get
            {
                return this.address;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.address, value, () => this.Address);
            }
        }

        public bool HasAddress
        {
            get { return this.address != null && this.address != Address.Empty; }
        }

        public static bool operator ==(RouteDestination rd1, RouteDestination rd2)
        {
            return Equals(rd1, rd2);
        }

        public static bool operator !=(RouteDestination rd1, RouteDestination rd2)
        {
            return !Equals(rd1, rd2);
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj))
            {
                return false;
            }

            return obj is RouteDestination && this.Equals((RouteDestination)obj);
        }

        public override int GetHashCode()
        {
            return this.CombineHashCodes(this.Address, this.Landmark, this.Point);
        }

        public bool Equals(RouteDestination destination)
        {
            if (ReferenceEquals(null, destination))
            {
                return false;
            }

            if (this.Address != destination.Address)
            {
                return false;
            }

            if (this.Landmark != destination.Landmark)
            {
                return false;
            }

            if (this.Point != destination.Point)
            {
                return false;
            }

            return true;
        }

        public RouteDestination ShallowClone()
        {
            var criterion = new RouteDestination
            {
                Address = this.Address,
                Landmark = this.Landmark,
                Point = Point
            };

            return criterion;
        }

        public RouteDestination DeepClone()
        {
            var destination = new RouteDestination();

            if (this.HasAddress)
                destination.Address = this.Address.DeepClone();

            if (this.HasLandmark)
                destination.Landmark = this.Landmark.DeepClone();

            if (this.HasPoint)
                destination.Point = new GeoCoordinate(Point.Latitude, Point.Longitude);

            return destination;
        }
    }
}